package com.javasea.netty.har.client.netty;

import com.javasea.netty.har.client.cache.ChannelHolder;
import com.javasea.netty.har.client.config.ClientConfig;
import com.javasea.netty.har.client.utils.TrayOperator;
import com.javasea.netty.har.common.entity.NioClient;
import com.javasea.netty.har.common.entity.Result;
import com.javasea.netty.har.common.entity.print.Command;
import com.javasea.netty.har.common.entity.Heart;
import com.javasea.netty.har.common.entity.proto.CommandProto;
import com.javasea.netty.har.common.entity.proto.HeartProto;
import com.javasea.netty.har.common.utils.*;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoop;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * @ClassName: PrinterClientHandler
 * @Author: longxiaonan
 * @Date: 2018/8/1 12:38
 * @Description:
 */
@Slf4j
public class PrinterClientHandler extends SimpleChannelInboundHandler {

    private String nioClientCode = BeanTools.getBean(ClientConfig.class).getNioClientCode();

    /**
     * 在收到需要打印的消息时,判断对象类型,如果是打印模板对象,则进行打印,如果是连接opc信息,则进行连接opc后对plc进行写值
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object o) {
        try {
            ChannelHolder.setChannel(ctx);
            ChannelHolder.setTimeoutRecord(System.currentTimeMillis());
            log.info("Server say : " + o.toString());
            if (o instanceof HeartProto.Heart) {
                Heart heart = Converter.protobuf2Pojo((HeartProto.Heart) o);
                // TODO 心跳处理
    //            ChannelMap.setChannelLock(((Heart) msg).getNioClientCode(), new ReentrantLock());
                return;
            }
            if(o instanceof CommandProto.Command){
                Command command = Converter.protobuf2Pojo((CommandProto.Command) o);
                handleReceiveCommand(ctx, command);
            }
        } finally {
            // 不需要收到释放，在父类中有释放操作，所以注释掉
//            ReferenceCountUtil.release(o);
            log.info("Server msg handle finish");
        }

    }

    private void handleReceiveCommand(ChannelHandlerContext ctx, Command o) {
        Result result = Result.builder().batchId("11").number("222").build();
        // 保存到缓存
        Sender.send(ctx, result);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ChannelHolder.setChannel(ctx);
        ChannelHolder.setTimeoutRecord(System.currentTimeMillis());
        //通道活跃的时候,发送租户id
        NioClient client = new NioClient();
        client.setNioClientCode(nioClientCode + "__" + GetIpUtil.getLocalIp());
        Sender.send(ctx, client);
        super.channelActive(ctx);
        log.info("客户端连接服务端[成功]!");
        TrayOperator.trayMessage("客户端连接服务端[成功]!");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("断线了。。。。。。");
        doReConnect(ctx);
        ctx.fireChannelInactive();
        ctx.channel().close();
        TrayOperator.trayMessage("客户端连接服务端[断开]!");
    }

    private void doReConnect(ChannelHandlerContext ctx) {
        //使用过程中断线重连
        final EventLoop eventLoop = ctx.channel().eventLoop();
        // 断线后，发起重连
        eventLoop.schedule(() -> {
            log.info("连接被服务端终止, 开始重连!");
            PrinterClient.doConnect();
        }, 5L, TimeUnit.SECONDS);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
            throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            switch (e.state()) {
                case READER_IDLE:
                    log.info(("READER_IDLE"));
                    break;
                case WRITER_IDLE:
                    /**发送心跳,保持长连接*/
                    Heart heart = BeanGenerator.genHeart(this.nioClientCode);
                    Sender.send(ctx, heart);
                    break;
                case ALL_IDLE:
                    System.out.println("ALL_IDLE");
                    break;
                default:
                    break;
            }
        }
        super.userEventTriggered(ctx, evt);
    }

}
